package com.parleys.android.client.provider;

import java.util.Arrays;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;

import com.parleys.android.client.provider.ParleysContract.Channels;
import com.parleys.android.client.provider.ParleysContract.News;
import com.parleys.android.client.provider.ParleysContract.Presentations;
import com.parleys.android.client.provider.ParleysContract.Spaces;
import com.parleys.android.client.provider.ParleysDatabase.Tables;
import com.parleys.android.client.util.SelectionBuilder;

public class ParleysProvider extends ContentProvider {

    private static final String		TAG 	= "ParleysProvider";
    private static final boolean 	LOGD 	= Log.isLoggable(TAG, Log.DEBUG);

    private ParleysDatabase mOpenHelper;
    private Context mContext;

    private static final UriMatcher sUriMatcher = buildUriMatcher();

    private static final int NEWS 						= 100;
    private static final int NEWS_ID 					= 101;

    private static final int SPACES 					= 200;
    private static final int SPACES_ID 					= 201;
    private static final int SPACES_ID_CHANNELS			= 202;

    private static final int CHANNELS 					= 300;
    private static final int CHANNELS_ID 				= 301;
    private static final int CHANNELS_ID_PRESENTATIONS	= 302;

    private static final int PRESENTATIONS				= 400;
    private static final int PRESENTATIONS_ID 			= 401;

    private static UriMatcher buildUriMatcher() {
        final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
        final String authority = ParleysContract.CONTENT_AUTHORITY;

        matcher.addURI(authority, "news", NEWS);
        matcher.addURI(authority, "news/*", NEWS_ID);
        
        matcher.addURI(authority, "spaces", SPACES);
        matcher.addURI(authority, "spaces/*", SPACES_ID);
        matcher.addURI(authority, "spaces/*/channels", SPACES_ID_CHANNELS);

        matcher.addURI(authority, "channels", CHANNELS);
        matcher.addURI(authority, "channels/*", CHANNELS_ID);
        matcher.addURI(authority, "channels/*/presentations", CHANNELS_ID_PRESENTATIONS);

        matcher.addURI(authority, "presentations", PRESENTATIONS);
        matcher.addURI(authority, "presentations/*", PRESENTATIONS_ID);

        return matcher;
    }

	@Override
	public boolean onCreate() {
		this.mContext = getContext();
		this.mOpenHelper = new ParleysDatabase(this.mContext);
		return true;
	}

	@Override
	public String getType(Uri uri) {
		final int match = sUriMatcher.match(uri);
		switch (match) {
			case NEWS:
				return News.CONTENT_TYPE;
			case NEWS_ID:
				return News.CONTENT_ITEM_TYPE;
			case SPACES:
				return Spaces.CONTENT_TYPE;
			case SPACES_ID:
				return Spaces.CONTENT_ITEM_TYPE;
			case SPACES_ID_CHANNELS:
				return Channels.CONTENT_TYPE;
			case CHANNELS:
				return Channels.CONTENT_TYPE;
			case CHANNELS_ID:
				return Channels.CONTENT_ITEM_TYPE;
			case CHANNELS_ID_PRESENTATIONS:
				return Presentations.CONTENT_TYPE;
			case PRESENTATIONS:
				return Presentations.CONTENT_TYPE;
			case PRESENTATIONS_ID:
				return Presentations.CONTENT_ITEM_TYPE;
		}
		return null;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
    	if (LOGD) {
    		Log.d(TAG, 
    			"insert(uri=" 
    			+ String.valueOf(uri) 
    			+ ", values=" 
    			+ String.valueOf(values) 
    			+ ")");
    	}

        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    	
    	final int match = sUriMatcher.match(uri);
        switch (match) {
			case NEWS: {
                db.insertOrThrow(Tables.NEWS, null, values);
                return uri.buildUpon().appendPath(String.valueOf(values.getAsInteger(News.NEWS_ID))).build();
			}
			case SPACES: {
                db.insertOrThrow(Tables.SPACES, null, values);
                return uri.buildUpon().appendPath(String.valueOf(values.getAsInteger(Spaces.SPACE_ID))).build();
			}
			case SPACES_ID_CHANNELS: {
	            final int spaceId = Spaces.getSpaceId(uri);
	            values.put(Channels.SPACE_ID, spaceId);
                db.insertOrThrow(Tables.CHANNELS, null, values);
                return uri;
//                return uri.buildUpon().appendPath(String.valueOf(values.getAsInteger(Channels.CHANNEL_ID))).build();
			}
			case CHANNELS: {
                db.insertOrThrow(Tables.CHANNELS, null, values);
                return uri.buildUpon().appendPath(String.valueOf(values.getAsInteger(Channels.CHANNEL_ID))).build();
			}
			case CHANNELS_ID_PRESENTATIONS: {
	            final int channelId = Channels.getChannelId(uri);
	            values.put(Presentations.CHANNEL_ID, channelId);
                db.insertOrThrow(Tables.PRESENTATIONS, null, values);
                return uri;
			}
			case PRESENTATIONS: {
                db.insertOrThrow(Tables.PRESENTATIONS, null, values);
                return uri.buildUpon().appendPath(String.valueOf(values.getAsInteger(Presentations.PRESENTATION_ID))).build();
			}
			default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
		}
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    	if (LOGD) {
			Log.d(TAG, 
					"update(uri=" 
					+ String.valueOf(uri) 
					+ ", values=" 
					+ String.valueOf(values) 
					+ ", selection=" 
					+ String.valueOf(selection)
					+ ", selectionArgs="
					+ Arrays.toString(selectionArgs)
					+ ")");
    	}

    	final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        final SelectionBuilder builder = buildSimpleSelection(uri);
        return builder.where(selection, selectionArgs).update(db, values);
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
    	if (LOGD) {
	    	Log.d(TAG, 
	    			"delete(uri=" 
	    			+ String.valueOf(uri)
	    			+ "selectionArgs="
	    			+ Arrays.toString(selectionArgs)
	    			+ ")");
    	}

        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        final SelectionBuilder builder = buildSimpleSelection(uri);
        return builder.where(selection, selectionArgs).delete(db);
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    	if (LOGD) {
	    	Log.d(TAG, 
	    			"query(uri=" 
	    			+ String.valueOf(uri)
	    			+ ", projection=" 
	    			+ Arrays.toString(projection) 
	    			+ ", selection=" 
	    			+ String.valueOf(selection)
	    			+ "selectionArgs="
	    			+ Arrays.toString(selectionArgs)
	    			+ ", sortOrder=" 
	    			+ String.valueOf(sortOrder)
	    			+ ")");
    	}
    	
        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();

        final int match = sUriMatcher.match(uri);
        final SelectionBuilder builder = buildExpandedSelection(uri, match);
        Cursor c = builder.where(selection, selectionArgs).query(db, projection, sortOrder);
        switch (match) {
			case NEWS:
				c.setNotificationUri(mContext.getContentResolver(), uri);
				break;
			case SPACES:
				c.setNotificationUri(mContext.getContentResolver(), uri);
				break;
			case CHANNELS:
				c.setNotificationUri(mContext.getContentResolver(), uri);
				break;
			case PRESENTATIONS:
				c.setNotificationUri(mContext.getContentResolver(), uri);
				break;
		}
        
        return c;
	}

    private SelectionBuilder buildSimpleSelection(Uri uri) {
        final SelectionBuilder builder = new SelectionBuilder();
        final int match = sUriMatcher.match(uri);
        switch (match) {
	        case NEWS: {
	            return builder.table(Tables.NEWS);
	        }
	        case NEWS_ID: {
	            final String newsId = News.getNewsId(uri);
	            return builder.table(Tables.NEWS)
	            	.where(News.NEWS_ID + "=?", newsId);
	        }
	        case SPACES: {
	            return builder.table(Tables.SPACES);
	        }
	        case SPACES_ID: {
	            final int spaceId = Spaces.getSpaceId(uri);
	            return builder.table(Tables.SPACES)
	            	.where(Spaces.SPACE_ID + "=?", String.valueOf(spaceId));
	        }
	        case SPACES_ID_CHANNELS: {
	            final int spaceId = Spaces.getSpaceId(uri);
	            return builder.table(Tables.CHANNELS)
	            	.where(Channels.SPACE_ID + "=?", String.valueOf(spaceId));
	        }
	        case CHANNELS: {
	            return builder.table(Tables.CHANNELS);
	        }
	        case CHANNELS_ID: {
	            final int channelId = Channels.getChannelId(uri);
	            return builder.table(Tables.CHANNELS)
	            	.where(Channels.CHANNEL_ID + "=?", String.valueOf(channelId));
	        }
	        case CHANNELS_ID_PRESENTATIONS: {
	            final int channelId = Channels.getChannelId(uri);
	            return builder.table(Tables.PRESENTATIONS)
	            	.where(Presentations.CHANNEL_ID + "=?", String.valueOf(channelId));
	        }
	        case PRESENTATIONS: {
	            return builder.table(Tables.PRESENTATIONS);
	        }
	        case PRESENTATIONS_ID: {
	            final int presentationId = Presentations.getPresentationId(uri);
	            return builder.table(Tables.PRESENTATIONS)
	            	.where(Presentations.PRESENTATION_ID + "=?", String.valueOf(presentationId));
	        }
	        default: {
	            throw new UnsupportedOperationException("Unknown uri: " + uri);
	        }
	    }
    }

    private SelectionBuilder buildExpandedSelection(Uri uri, int match) {
        final SelectionBuilder builder = new SelectionBuilder();
        switch (match) {
            case NEWS:
            case NEWS_ID:
            case SPACES:
            case SPACES_ID:
            case SPACES_ID_CHANNELS:
            case CHANNELS:
            case CHANNELS_ID:
            case CHANNELS_ID_PRESENTATIONS:
            case PRESENTATIONS:
            case PRESENTATIONS_ID:
            	return buildSimpleSelection(uri);
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
    }

}
